﻿using System;
using System.Collections.Generic;
using System.Threading;

//* Implement the "Falling Rocks" game in the text 
//console. A small dwarf stays at the bottom of the 
//screen and can move left and right (by the arrows 
//keys). A number of rocks of different sizes and forms 
//constantly fall down and you need to avoid a crash.

class FallingRocksGame
{
    public static int consoleHeight = 40;
    public static int consoleWidth = 50;
    public const int rocksPerRow = 5;

    static void Main()
    {
        bool gameIsRunning = true;
        Random random = new Random();

        Console.WindowHeight = consoleHeight;
        Console.WindowWidth = consoleWidth;
        Console.BufferHeight = consoleHeight;
        Console.BufferWidth = consoleWidth;
        Console.CursorVisible = false;

        Queue<Rock[]> rocks = new Queue<Rock[]>(consoleHeight);
        Rock[] rowOfRocks = new Rock[rocksPerRow];
        Rock[] lastRowOfRocks;

        int gameScore = 0;

        for (int i = 0; i < rocksPerRow; i++)
        {
            rowOfRocks[i] = new Rock();
        }

        //Add the dwarf
        Rock dwarf = new Rock(new ConsolePosition(consoleHeight - 2, consoleWidth / 2), "(O)", ConsoleColor.White);

        #region Main Loop
        while (gameIsRunning)
        {
            //Clear contents of window
            Console.Clear();

            //Add a new row of rocks
            rocks.Enqueue(rowOfRocks);

            //Check if dwarf is hit by a rock
            lastRowOfRocks = rocks.Peek();

            if (lastRowOfRocks.Length != 0 && lastRowOfRocks[0].position.Row == consoleHeight - 2)
            {
                for (int i = 0; i < lastRowOfRocks.Length; i++)
                {
                    int rockcolumn = lastRowOfRocks[i].position.Column;
                    int dwarfcolumn = dwarf.position.Column;

                    if (rockcolumn == dwarfcolumn || rockcolumn == dwarfcolumn + 1 || rockcolumn == dwarfcolumn + 2)
                    {
                        gameIsRunning = false;
                        break;
                    }
                }
            }

            //Draw dwarf
            dwarf.Draw();

            //Draw Rocks & Move them down
            foreach (Rock[] row in rocks)
            {
                for (int i = 0; i < row.Length; i++)
                {
                    row[i].Draw();
                    row[i].MoveDown();
                }
            }

            //Generate a new row of rocks
            rowOfRocks = new Rock[random.Next(0, rocksPerRow)];
            if (rowOfRocks.Length != 0)
            {
                for (int i = 0; i < rowOfRocks.Length; i++)
                {
                    rowOfRocks[i] = new Rock();
                }
            }

            //Check if any keys where pressed
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo pressedKey = Console.ReadKey();
                if (pressedKey.Key == ConsoleKey.RightArrow)
                {
                    dwarf.MoveRight();
                }
                if (pressedKey.Key == ConsoleKey.LeftArrow)
                {
                    dwarf.MoveLeft();
                }

                while (Console.KeyAvailable)
                {
                    Console.ReadKey(true);
                }
            }

            if (rocks.Count == consoleHeight - 1)
            {
                rocks.Dequeue();
                gameScore += 10;
            }
            Thread.Sleep(150);
        }
        #endregion

        Console.Clear();
        Console.WriteLine("Game Over! Your score is " + gameScore);
    }

    public class ConsolePosition
    {
        public int Row;
        public int Column;

        public ConsolePosition()
        {
            Row = 0;
            Column = 0;
        }

        public ConsolePosition(int row, int column)
        {
            this.Row = row;
            this.Column = column;
        }
    }

    public class Rock
    {
        static string[] rockChars = { "^", "@", "*", "&", "+", "%", "$", "#", "!", ".", ";" };
        static ConsoleColor[] rockColors = (ConsoleColor[])Enum.GetValues(typeof(ConsoleColor));
        static Random random = new Random();


        public string rockSymbol;
        public ConsolePosition position;
        public ConsoleColor color;

        public Rock()
        {
            rockSymbol = rockChars[random.Next(10)];
            position = new ConsolePosition(0, random.Next(FallingRocksGame.consoleWidth));
            color = rockColors[random.Next(1,16)];
        }

        public Rock(ConsolePosition charpos, string rockchar, ConsoleColor charcolor)
        {
            this.position = charpos;
            this.rockSymbol = rockchar;
            this.color = charcolor;
        }

        public void Draw()
        {
            Console.SetCursorPosition(position.Column, position.Row);
            Console.ForegroundColor = color;
            Console.Write(rockSymbol);
        }

        public void MoveDown()
        {
            position.Row++;
        }

        public void MoveLeft()
        {
            if (position.Column > 0)
            {
                position.Column--;
            }
        }

        public void MoveRight()
        {
            if (position.Column < consoleWidth - 3)
            {
                position.Column++;
            }
        }
    }

    public class RandomGenerator
    {
        uint randomNumber;

        public RandomGenerator()
        {
            randomNumber = 27;
        }

        public uint Next()
        {
            randomNumber ^= (randomNumber << 10);
            randomNumber ^= (randomNumber >> 6);
            randomNumber ^= (randomNumber << 2);
            return randomNumber;
        }

        public int Next(int maxValue)
        {

            randomNumber ^= (randomNumber << 15);
            randomNumber ^= (randomNumber >> 6);
            randomNumber ^= (randomNumber << 2);
            int result = (int)randomNumber % maxValue;
            return (result <= 0) ? -result - 1 : result;
        }
    }
}
